/**
 * Project: Utilities <br>
 * Package: org.leumasjaffe.functions
 */
package org.leumasjaffe.functional;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
 * Class org.leumasjaffe.functions.Predicate in file Predicate.java <br>
 * 
 * @author leumasjaffe
 * @version Jun 9, 2013
 * Created on: Jun 9, 2013
 * 
 * @param <T>
 */
@NonNullByDefault
public interface Predicate<T> {
	
	/**
	 * Class org.leumasjaffe.functional.Predicate.Not in file Predicate.java <br>
	 * 
	 * @author leumasjaffe
	 * @version Jan 18, 2014
	 * Created on: Jan 18, 2014
	 * 
	 * @param <T> The type to test against
	 */
	final class Not<T> implements Predicate<T> {
		private final Predicate<T> pred;

		/**
		 * Constructs a new predicate inversion
		 * @param pred A predicate to invert
		 */
		private Not(Predicate<T> pred) {
			this.pred = pred;
		}
		
		/**
		 * Obtains a view of a {@link Predicate} with the property that for every T t, 
		 * pred.test(t) != Not.of(pred).test(t) <br>
		 * @param pred A predicate to be inverted
		 * @param <T> The type that is being tested against
		 * @return An instance of the Not class unless the input parameter is of type Not,
		 * in which case it returns Not.pred to prevent nesting.
		 */
		public static <T> Predicate<T> of(Predicate<T> pred) {
			return pred instanceof Not ? ((Not<T>) pred).pred : new Not<>(pred);
		}

		/* (non-Javadoc)
		 * @see org.leumasjaffe.functional.Predicate#test(java.lang.Object)
		 */
		@Override
		public boolean test(T arg0) {
			return !this.pred.test(arg0);
		}
	}
	
	/**
	 * Tests the argument that is has a given property
	 * @param arg0 An instance of the desired type
	 * @return Whether or not the argument passes the test
	 */
	boolean test(T arg0); // $codepro.audit.disable booleanMethodNamingConvention
}
